/*
 * Copyright (c) 2017 The sky Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sky.account.manager.controller

import com.sky.account.manager.Constant
import com.sky.account.manager.base.BaseController
import com.sky.account.manager.model.AccountModel
import com.sky.account.manager.model.AdminModel
import com.sky.account.manager.util.DialogUtil
import com.sky.account.manager.util.Log
import io.reactivex.schedulers.Schedulers
import javafx.application.Platform
import javafx.collections.FXCollections
import javafx.event.ActionEvent
import javafx.fxml.FXML
import javafx.fxml.Initializable
import javafx.scene.control.*
import javafx.scene.control.cell.PropertyValueFactory
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.input.MouseButton
import javafx.scene.input.MouseEvent
import javafx.stage.FileChooser
import javafx.stage.Stage
import java.awt.Desktop
import java.io.File
import java.net.URI
import java.net.URL
import java.text.SimpleDateFormat
import java.util.*


/**
 * Created by sky on 17-8-17.
 */
class HomeController : BaseController<Any>(), Initializable {

    @FXML lateinit var menu:Menu
    @FXML lateinit var settings:Menu
    @FXML lateinit var help:Menu

    @FXML lateinit var miNewAccount: MenuItem
    @FXML lateinit var mtModifyPassword: MenuItem
    @FXML lateinit var miImportAccount: MenuItem
    @FXML lateinit var miExportAccount: MenuItem
    @FXML lateinit var miExit: MenuItem
    @FXML lateinit var miSettings: MenuItem
    @FXML lateinit var miAbout: MenuItem

    @FXML lateinit var jtfSearchKey: TextField
    @FXML lateinit var jBtmSearch: Button
    @FXML lateinit var tVersion: Label

    @FXML lateinit var tvTable: TableView<AccountModel>
    @FXML lateinit var name: TableColumn<AccountModel, String>
    @FXML lateinit var password: TableColumn<AccountModel, String>
    @FXML lateinit var url: TableColumn<AccountModel, String>
    @FXML lateinit var desc: TableColumn<AccountModel, String>
    @FXML lateinit var jtaExpand: TextArea

    private lateinit var tvTableSelection: TableView.TableViewSelectionModel<AccountModel>

    companion object {
        val DATA_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    }

    override fun initialize(location: URL?, resources: ResourceBundle?) {

        // 设置版本号
        tVersion.text = "Version: ${Constant.App.VERSION}"

        // 初始化表结构
        name.cellValueFactory = PropertyValueFactory<AccountModel, String>("name")
        password.cellValueFactory = PropertyValueFactory<AccountModel, String>("password")
        url.cellValueFactory = PropertyValueFactory<AccountModel, String>("url")
        desc.cellValueFactory = PropertyValueFactory<AccountModel, String>("desc")

        tvTableSelection = tvTable.selectionModel
    }

    override fun initParam(stage: Stage, param: Any) {
        super.initParam(stage, param)

        // 默认搜索
        Platform.runLater { onSearchAction() }
    }

    fun onMenuAction(event: ActionEvent) {

        when(event.source) {
            miNewAccount -> {
                // 创建账号
                showEditAccountDialog(getTitle("menu.newAccount"), AccountModel()) {
                    Platform.runLater { createAccount(it) }
                }
            }
            mtModifyPassword -> {
                // 修改密码
                getAppController().showDialog(
                        getTitle("menu.modifyPassword"),
                        "layout/edit_admin.fxml", 400.0, 300.0,
                        getAccountManager().getAdmin()) {
                    // 执行修改密码操作
                    changeAdminPassword(it)
                }
            }
            miImportAccount -> {
                // 导入账号
                val fileChooser = FileChooser()
                fileChooser.title = "选择导入的文件"
                fileChooser.selectedExtensionFilter =
                        FileChooser.ExtensionFilter("*.txt,*.json", "json", "txt")
                importAccount(fileChooser.showOpenDialog(getStage()))
            }
            miExportAccount -> {
                // 导出账号
                val fileChooser = FileChooser()
                fileChooser.title = "选择导出的目录"
                fileChooser.selectedExtensionFilter =
                        FileChooser.ExtensionFilter("*.txt,*.json", "json", "txt")
                exportAccount(fileChooser.showSaveDialog(getStage()))
            }
            miExit -> {
                // 退出程序
                getAppController().exitApp()
            }
            miSettings -> {
                // 程序设置
                DialogUtil.showMessage(Alert.AlertType.INFORMATION, "功能暂未实现!")
            }
            miAbout -> {
                // 关于
                showDialog(
                        getTitle("app.about"), "layout/about.fxml", 400.0, 300.0)
            }
        }
    }

    private fun onMenuAction(item: MenuItem, event: ActionEvent) {

        if (!isTabSelected()) return

        val accountManager = getAccountManager()

        // 获取选择的内容
        val selectedItem = getTabSelectedItem()

        when(item.text) {
            getString("menu.open") -> {
                // 打开浏览器,目前打开浏览器有问题
                try {
                    Desktop.getDesktop()
                            .browse(URI(selectedItem.url))
                } catch (tr: Throwable) {
                    Log.e("打开页面异常", tr)
                }
            }
            getString("menu.display") -> {
                // 显示账号详情
                getAppController().showDialog(
                        getTitle("app.details"), "layout/details.fxml",
                        400.0, 260.0,
                        accountManager.decryptionAccount(selectedItem))
            }
            getString("menu.modify") -> {
                // 编辑账号
                showEditAccountDialog(
                        getTitle("app.modify"),
                        accountManager.decryptionAccount(selectedItem)) {
                    Platform.runLater { editAccount(it) }
                }
            }
            getString("menu.delete") -> {
                // 删除账号
                accountManager.deleteAccount(selectedItem)
                Platform.runLater { onSearchAction() }
            }
        }
    }

    fun onSearchKeyPressedAction(event: KeyEvent) {

        if (KeyCode.ENTER == event.code) {
            // 直接调用搜索
            Platform.runLater { onSearchAction() }
        }
    }

    fun onSearchAction() {

        val accountManager = getAccountManager()

        // 搜索相应的账号
        val accountModels = accountManager.search(0, jtfSearchKey.text)

        // 设置信息
        tvTable.items = FXCollections.observableArrayList(accountModels)

        // 设置扩展信息
        setExpandAccountInfo(getTabSelectedIndex())
    }

    fun onTableMouseEvent(event: MouseEvent) {

        if (MouseButton.SECONDARY == event.button
                && isTabSelected()) {

            val menu = ContextMenu(
                    buildMenuItem(getString("menu.open")),  // 调用浏览器打开有问题
                    buildMenuItem(getString("menu.display")),
                    buildMenuItem(getString("menu.modify")),
                    buildMenuItem(getString("menu.delete")))

            // 显示菜单
            menu.show(getStage(), event.screenX, event.screenY)
        }

        setExpandAccountInfo(getTabSelectedIndex())
    }

    fun onTableKeyReleasedEvent(event: KeyEvent) {

        if (KeyCode.UP == event.code
                || KeyCode.DOWN == event.code) {
            // 更新扩展信息
            setExpandAccountInfo(getTabSelectedIndex())
        }
    }

    private fun buildMenuItem(name: String): MenuItem {

        val menuItem = MenuItem(name)

        menuItem.addEventHandler(ActionEvent.ACTION) {

            // 处理菜单事件
            onMenuAction(it.source as MenuItem, it)
        }

        return menuItem
    }

    private fun showEditAccountDialog(title: String, account: AccountModel, callback: (AccountModel) -> Unit) {

        getAppController().showDialog(
                title, "layout/edit_account.fxml",
                400.0, 300.0,
                account, callback)
    }

    private fun createAccount(account: AccountModel) {

        val accountManager = getAccountManager()

        // 重新设置时间
        account.adminId = accountManager.getAdmin().id
        account.createTime = System.currentTimeMillis()

        if (accountManager.createAccount(account)) {
            // 刷新列表
            Platform.runLater { onSearchAction() }
            return
        }

        DialogUtil.showMessage(
                Alert.AlertType.ERROR, "创建账号异常，请查看相关日志信息！")
    }

    private fun editAccount(account: AccountModel) {

        val accountManager = getAccountManager()

        if (accountManager.updateAccount(account)) {
            // 刷新列表
            Platform.runLater { onSearchAction() }
            return
        }

        DialogUtil.showMessage(
                Alert.AlertType.ERROR, "修改账号异常，请查看相关日志信息！")
    }

    private fun setExpandAccountInfo(index: Int) {

        if (index < 0) {
            // 设置扩展内容
            jtaExpand.text = ""
            return
        }

        // 获取选择内容
        val account = getTabSelectedItem()

        val info = StringBuilder().apply {
            append("${getString("label.userName")} ${account.name}\n")
            append("${getString("label.password")} ${account.password}\n")
            append("${getString("label.url")} ${account.url}\n")
            append("${getString("label.desc")} ${account.desc}\n")
            append("${getString("label.createTime")} ${DATA_FORMAT.format(account.createTime)}")
        }

        // 设置扩展内容
        jtaExpand.text = info.toString()
    }

    private fun getTabSelectedIndex(): Int {
        return tvTableSelection.selectedIndex
    }

    private fun getTabSelectedItem(): AccountModel {
        return tvTableSelection.selectedItem
    }

    private fun isTabSelected(): Boolean {
        return tvTableSelection.selectedIndex > -1
    }

    private fun changeAdminPassword(newAdmin: AdminModel) {

        val accountManager = getAccountManager()

        showLoading()

        accountManager
                .changeAdminPassword(newAdmin)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.from { Platform.runLater { it.run() } })
                .subscribe(
                        {
                            cancelLoading()
                            // 成功了
                            onSearchAction()
                        },
                        {
                            cancelLoading()
                            // 出错了
                            DialogUtil.showException(
                                    "修改密码异常", "修改密码异常!", Thread.currentThread(), it)
                        }
                )
    }

    private fun importAccount(file: File?) {

        if (file == null) return

        if (file.length() > 1024 * 2014) {
            // 文件过大
            DialogUtil.showMessage(Alert.AlertType.ERROR, "文件过大,无法导入!")
            return
        }

        val accountManager = getAccountManager()

        showLoading()

        accountManager
                .importAccount(file)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.from { Platform.runLater { it.run() } })
                .subscribe(
                        {
                            cancelLoading()
                            // 成功了
                            onSearchAction()

                            // 成功了
                            DialogUtil.showMessage(
                                    Alert.AlertType.INFORMATION, "导入账号成功了!")
                        },
                        {
                            cancelLoading()
                            // 出错了
                            DialogUtil.showException(
                                    "导入失败", "导入账号异常!", Thread.currentThread(), it)
                        }
                )
    }

    private fun exportAccount(file: File?) {

        if (file == null) return

        val accountManager = getAccountManager()

        showLoading()

        accountManager
                .exportAccount(file)
                .subscribeOn(Schedulers.io())
                .observeOn(Schedulers.from { Platform.runLater { it.run() } })
                .subscribe(
                        {
                            cancelLoading()
                            // 成功了
                            DialogUtil.showMessage(
                                    Alert.AlertType.INFORMATION, "导出账号成功了!")
                        },
                        {
                            cancelLoading()
                            // 出错了
                            DialogUtil.showException(
                                    "导出失败", "导出账号异常!", Thread.currentThread(), it)
                        }
                )
    }
}
